﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_GL_RENDER_STATE_H
#define _UXS_GL_RENDER_STATE_H

#pragma once

#include "GLCommon.h"

namespace UX_STL
{
namespace GLShell
{
	
	namespace e_color_mask
	{
		enum	type	: uint8
		{
			NONE	= 0,

			R		= 0x01,
			G		= 0x02,
			B		= 0x04,
			A		= 0x08,
			RGBA	= R | G | B | A,

			RG		= R | G,
			RB		= R | B,
			RGB		= R | G | B,
			GB		= G | B,
			GA		= G | A,
			GBA		= G | B | A,
			BA		= B | A,
		};

		UX_ENUM_BIT_OPERATIONS( type )
	}


	namespace e_cull_mode
	{
		enum	type	: uint8
		{
			NONE			= 0x0,
			BACK			= 0x01,
			FRONT			= 0x02,
			FRONT_AND_BACK	= BACK | FRONT,
			_CULL_MASK		= 0x0F,

			FACE_CCW		= 0x10,
			FACE_CW			= 0x20,
			_FACE_MASK		= 0xF0,

			DEFAULT			= BACK | FACE_CCW,

			FACE_CCW_CULL_BACK			 = FACE_CCW | BACK,
			FACE_CCW_CULL_FRONT			 = FACE_CCW | FRONT,
			FACE_CCW_CULL_FRONT_AND_BACK = FACE_CCW | FRONT | BACK,
		};

		UX_ENUM_BIT_OPERATIONS( type )
	}



	//
	// GL Render State
	//

	class GLRenderState //: public GLBaseObject
	{
	public:
		struct TColorBuffer
		{
			gl_blend_func::type		eSrcRGB,
									eSrcAlpha,
									eDstRGB,
									eDstAlpha;
			gl_blend_equation::type	eModeRGB,
									eModeAlpha;
			e_color_mask::type		eMask;
			uint8					uIndex;
			bool					bBlending;
			///
			TColorBuffer():
				uIndex(-1),								bBlending(false),
				eSrcRGB(gl_blend_func::ONE),			eSrcAlpha(gl_blend_func::ONE),
				eDstRGB(gl_blend_func::ZERO),			eDstAlpha(gl_blend_func::ZERO),
				eModeRGB(gl_blend_equation::ADD),		eModeAlpha(gl_blend_equation::ADD),
				eMask(e_color_mask::RGBA)
			{}
		};

		struct TStencilState
		{
			struct TSide
			{
				gl_stencil_op::type		eSFail,		// stencil test fail
										eDFail,		// stencil tess passes, but depth test fail
										eDPPass;	// stencil test and depth test pass
				gl_compare::type		eFunc;		// (ref & mask) op (stencil & mask)
				uint8					uFuncRef;
				uint8					uFuncMask;
				uint8					uMask;
				///
				TSide():
					eSFail(gl_stencil_op::KEEP),	eDFail(gl_stencil_op::KEEP),
					eDPPass(gl_stencil_op::KEEP),	eFunc(gl_compare::ALWAYS),
					uFuncRef(0),	uFuncMask(-1), uMask(-1)
				{}
			};

			static_array<TSide,2>	aSide;	// front, back
			bool					bTest;
			///
			TStencilState(): bTest(false) {}
		};

		struct TDepthState
		{
			gl_compare::type		eFunc;
			bool					bWrite;
			bool					bTest;
			///
			TDepthState(): eFunc(gl_compare::LEQUAL), bWrite(true), bTest(true) {}
		};

		struct TStates
		{
			bool					bDepthClamp,
									bDither,
									bPolygonOffset,	// for point, line, fill polygon mode
									bSmooth,		// for point, line, fill polygon mode
									bCubemapSeamless,
									bProgramPointSize,
									bFramebufferSRGB;
			///
			TStates():
				bDepthClamp(false),	bDither(false), bPolygonOffset(false), bSmooth(false),
				bCubemapSeamless(false), bProgramPointSize(false), bFramebufferSRGB(false)
			{}
		};


		static_array< TColorBuffer, 8 >	aColorBuffers;
		TStencilState					sStencil;
		TDepthState						sDepth;
		TStates							sStates;
		fvec2							vPolygonOffset;
		e_cull_mode::type				eCullMode;
		gl_polygon_mode::type			ePolygon;
		///
		GLRenderState():
			ePolygon(gl_polygon_mode::FILL),	eCullMode(e_cull_mode::DEFAULT)
		{}
			
		void Apply() const;
		
		void Invalidate();
		void Validate();

		//static CMetaSetIterator * s_GetIterator(const GLRenderState &sRS);
		//static void s_InitMetaData();
	};


}	// GLShell


	UX_ENUM_META_OBJECT( GLShell::e_color_mask::type );
	UX_ENUM_META_OBJECT( GLShell::e_cull_mode::type );
	UX_DECLARE_META_OBJECT( GLShell::GLRenderState );
	UX_DECLARE_META_OBJECT( GLShell::GLRenderState::TColorBuffer );
	UX_DECLARE_META_OBJECT( GLShell::GLRenderState::TStencilState );
	UX_DECLARE_META_OBJECT( GLShell::GLRenderState::TStencilState::TSide );
	UX_DECLARE_META_OBJECT( GLShell::GLRenderState::TDepthState );
	UX_DECLARE_META_OBJECT( GLShell::GLRenderState::TStates );
	
//-------------------------------------------------------------------

}	// UX_STL

#endif	// _UXS_GL_RENDER_STATE_H